import {
    _decorator,
    Camera,
    Color,
    Component,
    Director,
    director,
    find,
    ImageAsset,
    instantiate,
    isValid,
    Layers,
    Node,
    Pool,
    Rect,
    RenderTexture,
    Sprite,
    SpriteFrame,
    sys,
    Texture2D,
    UITransform,
    view,
} from 'cc';
const { ccclass, property } = _decorator;

const pool = new Pool<Node>(
    () => {
        let node = new Node();
        node.name = 'CaptureNode';
        node.addComponent(Sprite);
        node.layer = Layers.Enum.UI_2D;
        return node;
    },
    8,
    (node: Node) => {
        if (!node || !isValid(node)) {
            return false;
        }
        node.name = 'CaptureNode';
        let sprite = node.getComponent(Sprite);
        sprite.spriteFrame?.texture?.destroy(); // 这里会把 renderTexture 销毁
        sprite.spriteFrame?.destroy();
        sprite.spriteFrame = null;
        node.removeFromParent();
        return true;
    },
);

@ccclass('CaptureNode')
export class CaptureNode extends Component {
    private _captureLayer: number = -1;

    public get CAPTURE_LAYER(): number {
        if (this._captureLayer != -1) {
            return 1 << this._captureLayer;
        }

        // 跳过 索引 0
        for (let i = 1; i < 19; i++) {
            let name = Layers.layerToName(i);
            if (name === 'CAPTURE_LAYER') {
                this._captureLayer = i;
                break;
            }
            if (typeof name === 'undefined') {
                this._captureLayer = i;
                Layers.addLayer('CAPTURE_LAYER', this._captureLayer);
                break;
            }
        }

        if (this._captureLayer === -1) {
            throw new Error('无法增加新图层');
        }

        return 1 << this._captureLayer;
    }

    get captureCamera() {
        return this.getCaptureCamera();
    }

    getCaptureCamera(name = null) {
        name = name || 'DEFAULT_CAPTURE_CAMERA';
        let cameraNode: Node = find('Canvas/' + name);
        let camera: Camera = null;
        if (cameraNode) {
            camera = cameraNode.getComponent(Camera);
        } else {
            cameraNode = new Node();
            camera = cameraNode.addComponent(Camera);
            cameraNode.parent = find('Canvas');
        }

        camera.projection = Camera.ProjectionType.ORTHO;
        camera.clearFlags = Camera.ClearFlag.DEPTH_ONLY;
        camera.clearColor = Color.BLACK;
        camera.clearDepth = 1;
        camera.clearStencil = 0;

        camera.node.setPosition(0, 0, 1000);
        let size = view.getVisibleSize();
        camera.orthoHeight = size.height * 0.5;

        camera.visibility = Layers.Enum.UI_2D;
        cameraNode.setSiblingIndex(999);

        cameraNode.layer = Layers.Enum.DEFAULT;
        cameraNode.name = name;

        cameraNode.active = false;
        return camera;
    }

    private createCopyNode(node: Node): [Node, Rect] {
        // 现在只能对单个节点进行截图
        // TODO 对节点树进行截图
        let trans = node.getComponent(UITransform);
        let width = trans.width;
        let height = trans.height;
        let worldPos = node.getWorldPosition();
        let rect = new Rect(
            Math.ceil(worldPos.x - width * trans.anchorX),
            Math.ceil(worldPos.y - height * trans.anchorY),
            width,
            height,
        );

        // 拷贝一个 节点出来专门用作截图
        let copyNode = instantiate(node);
        copyNode.active = true;
        // 设置为截图图层
        copyNode.layer = this.CAPTURE_LAYER;
        copyNode.parent = node.parent;

        return [copyNode, rect];
    }

    //截取屏幕 同步,会跳帧
    //未实现预期效果,暂不可以
    captureScreenSync(
        rect?: Rect,
        options?: { layer?: Layers.Enum; camera?: Camera },
    ) {
        let camera = options?.camera;
        if (!camera) {
            camera = this.getCaptureCamera();
            camera.node.active = true;
        }
        let rt = new RenderTexture();
        const { width, height } = view.getVisibleSize();

        if (!rect) {
            rect = new Rect(0, 0, width, height);
        }
        // //  防止重复重置
        if (rt.width != width || rt.height != height) {
            rt.reset({ width, height });
        }

        let node = pool.alloc();
        node.layer = Layers.Enum.UI_2D;
        camera.targetTexture = rt;

        // 摄像机设置为 只显示截图图层
        if (options?.layer) {
            camera.visibility = options.layer;
        } else {
            camera.visibility = Layers.Enum.UI_2D;
        }

        // game.step();
        // director.emit(Director.EVENT_AFTER_UPDATE);
        director.root.frameMove(0.016);
        let _buffer = rt.readPixels(
            rect.x,
            rect.y,
            rect.width,
            rect.height,
        );
        let sprite = node.getComponent(Sprite);
        let img = new ImageAsset();
        img.reset({
            _data: _buffer,
            width: rect.width,
            height: rect.height,
            format: Texture2D.PixelFormat.RGBA8888,
            _compressed: false,
        });
        let texture = new Texture2D();
        texture.image = img;
        let sf = new SpriteFrame();
        sf.texture = texture;
        sf.packable = false;
        sf.flipUVY = true;
        if (
            sys.isNative &&
            (sys.os === sys.OS.IOS || sys.os === sys.OS.OSX)
        ) {
            sf.flipUVY = false;
        }
        sprite.spriteFrame = sf;
        camera.node.active = false;

        let trans = node.getComponent(UITransform);
        trans.width = rect.width;
        trans.height = rect.height;

        // tnt.renderTextureMgr.recycle(rt);
        rt.destroy();

        return node;
    }

    /**
     * 异步截取屏幕
     *
     * @param {Rect} [rect]
     * @param {{ layer?: Layers.Enum,callback?: Runnable1<Node> }} [options]
     * @return {*}
     * @memberof CaptureMgr
     */
    captureScreenAsync(
        callback?: (param: Node) => any,
        rect?: Rect,
        options?: {
            layer?: Layers.Enum;
            camera?: Camera;
        },
    ) {
        let camera = options?.camera;
        if (!camera) {
            camera = this.getCaptureCamera();
        }
        camera.node.active = true;
        let rt = new RenderTexture();
        const { width, height } = view.getVisibleSize();
        if (!rect) {
            rect = new Rect(0, 0, width, height);
        }

        //  防止重复重置
        if (rt.width != width || rt.height != height) {
            rt.reset({ width, height });
        }

        camera.targetTexture = rt;
        let node = pool.alloc();
        node.layer = Layers.Enum.UI_2D;

        // 摄像机设置为 只显示截图图层
        if (options?.layer) {
            camera.visibility = options.layer;
        }

        // // 下一帧才有数据
        let sprite = node.getComponent(Sprite);
        director.once(Director.EVENT_AFTER_DRAW, () => {
            let _buffer = rt.readPixels(
                rect.x,
                rect.y,
                rect.width,
                rect.height,
            );
            let img = new ImageAsset();
            img.reset({
                _data: _buffer,
                width: rect.width,
                height: rect.height,
                format: Texture2D.PixelFormat.RGBA8888,
                _compressed: false,
            });
            let texture = new Texture2D();
            texture.image = img;
            let sf = new SpriteFrame();
            sf.texture = texture;
            sf.packable = false;
            sf.flipUVY = true;
            if (
                sys.isNative &&
                (sys.os === sys.OS.IOS || sys.os === sys.OS.OSX)
            ) {
                sf.flipUVY = false;
            }
            sprite.spriteFrame = sf;
            camera.node.active = false;
            node.getComponent(UITransform)?.setContentSize(rect.size);
            // // 截图完成回收 rt
            rt.destroy();

            callback?.(node);
        });
        return node;
    }
}
